// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(sandersd): Refactor to remove recomputed codec arrays, and generally
// shorten and improve coverage.
//   - http://crbug.com/417444
//   - http://crbug.com/457438
// TODO(sandersd): Add tests to cover codec vectors with empty items.
// http://crbug.com/417461

#include <string>
#include <vector>

#include "base/logging.h"
#include "media/base/eme_constants.h"
#include "media/base/key_systems.h"
#include "media/base/media.h"
#include "media/base/media_client.h"
#include "ppapi/features/features.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

// These are the (fake) key systems that are registered for these tests.
// kUsesAes uses the AesDecryptor like Clear Key.
// kExternal uses an external CDM, such as Pepper-based or Android platform CDM.
const char kUsesAes[] = "x-org.example.clear";
const char kUseAesNameForUMA[] = "UseAes";
const char kExternal[] = "x-com.example.test";
const char kExternalNameForUMA[] = "External";

const char kClearKey[] = "org.w3.clearkey";
const char kExternalClearKey[] = "org.chromium.externalclearkey";

const char kAudioWebM[] = "audio/webm";
const char kVideoWebM[] = "video/webm";
const char kAudioFoo[] = "audio/foo";
const char kVideoFoo[] = "video/foo";

// Pick some arbitrary bit fields as long as they are not in conflict with the
// real ones.
enum TestCodec {
    TEST_CODEC_FOO_AUDIO = 1 << 10, // An audio codec for foo container.
    TEST_CODEC_FOO_AUDIO_ALL = TEST_CODEC_FOO_AUDIO,
    TEST_CODEC_FOO_VIDEO = 1 << 11, // A video codec for foo container.
    TEST_CODEC_FOO_VIDEO_ALL = TEST_CODEC_FOO_VIDEO,
    TEST_CODEC_FOO_ALL = TEST_CODEC_FOO_AUDIO_ALL | TEST_CODEC_FOO_VIDEO_ALL
};

static_assert((TEST_CODEC_FOO_ALL & EME_CODEC_ALL) == EME_CODEC_NONE,
    "test codec masks should only use invalid codec masks");

class TestKeySystemProperties : public KeySystemProperties {
public:
    bool IsSupportedInitDataType(EmeInitDataType init_data_type) const override
    {
        return init_data_type == EmeInitDataType::WEBM;
    }
    SupportedCodecs GetSupportedCodecs() const override
    {
        return EME_CODEC_WEBM_ALL | TEST_CODEC_FOO_ALL;
    }
    EmeConfigRule GetRobustnessConfigRule(
        EmeMediaType media_type,
        const std::string& requested_robustness) const override
    {
        return requested_robustness.empty() ? EmeConfigRule::SUPPORTED
                                            : EmeConfigRule::NOT_SUPPORTED;
    }
    EmeSessionTypeSupport GetPersistentReleaseMessageSessionSupport()
        const override
    {
        return EmeSessionTypeSupport::NOT_SUPPORTED;
    }
};

class AesKeySystemProperties : public TestKeySystemProperties {
public:
    AesKeySystemProperties(const std::string& name)
        : name_(name)
    {
    }

    std::string GetKeySystemName() const override { return name_; }
    EmeSessionTypeSupport GetPersistentLicenseSessionSupport() const override
    {
        return EmeSessionTypeSupport::NOT_SUPPORTED;
    }
    EmeFeatureSupport GetPersistentStateSupport() const override
    {
        return EmeFeatureSupport::NOT_SUPPORTED;
    }
    EmeFeatureSupport GetDistinctiveIdentifierSupport() const override
    {
        return EmeFeatureSupport::NOT_SUPPORTED;
    }
    bool UseAesDecryptor() const override { return true; }

private:
    std::string name_;
};

class ExternalKeySystemProperties : public TestKeySystemProperties {
public:
    std::string GetKeySystemName() const override { return kExternal; }
    EmeSessionTypeSupport GetPersistentLicenseSessionSupport() const override
    {
        return EmeSessionTypeSupport::SUPPORTED;
    }
    EmeFeatureSupport GetPersistentStateSupport() const override
    {
        return EmeFeatureSupport::ALWAYS_ENABLED;
    }
    EmeFeatureSupport GetDistinctiveIdentifierSupport() const override
    {
        return EmeFeatureSupport::ALWAYS_ENABLED;
    }
    std::string GetPepperType() const override
    {
        return "application/x-ppapi-external-cdm";
    }
};

// Adapt IsSupportedKeySystemWithMediaMimeType() to the new API,
// IsSupportedCodecCombination().
static bool IsSupportedKeySystemWithMediaMimeType(
    const std::string& mime_type,
    const std::vector<std::string>& codecs,
    const std::string& key_system)
{
    return (KeySystems::GetInstance()->GetContentTypeConfigRule(
                key_system, EmeMediaType::VIDEO, mime_type, codecs)
        != EmeConfigRule::NOT_SUPPORTED);
}

static bool IsSupportedKeySystemWithAudioMimeType(
    const std::string& mime_type,
    const std::vector<std::string>& codecs,
    const std::string& key_system)
{
    return (KeySystems::GetInstance()->GetContentTypeConfigRule(
                key_system, EmeMediaType::AUDIO, mime_type, codecs)
        != EmeConfigRule::NOT_SUPPORTED);
}

static bool IsSupportedKeySystem(const std::string& key_system)
{
    return KeySystems::GetInstance()->IsSupportedKeySystem(key_system);
}

// Adds test container and codec masks.
// This function must be called after SetMediaClient() if a MediaClient will be
// provided.
// More details: AddXxxMask() will create KeySystems if it hasn't been created.
// During KeySystems's construction GetMediaClient() will be used to add key
// systems. In test code, the MediaClient is set by SetMediaClient().
// Therefore, SetMediaClient() must be called before this function to make sure
// MediaClient in effect when constructing KeySystems.
static void AddContainerAndCodecMasksForTest()
{
    // Since KeySystems is a singleton. Make sure we only add test container and
    // codec masks once per process.
    static bool is_test_masks_added = false;

    if (is_test_masks_added)
        return;

    AddCodecMask(EmeMediaType::AUDIO, "fooaudio", TEST_CODEC_FOO_AUDIO);
    AddCodecMask(EmeMediaType::VIDEO, "foovideo", TEST_CODEC_FOO_VIDEO);
    AddMimeTypeCodecMask("audio/foo", TEST_CODEC_FOO_AUDIO_ALL);
    AddMimeTypeCodecMask("video/foo", TEST_CODEC_FOO_VIDEO_ALL);

    is_test_masks_added = true;
}

static bool CanRunExternalKeySystemTests()
{
#if defined(OS_ANDROID)
    if (HasPlatformDecoderSupport())
        return true;

    EXPECT_FALSE(IsSupportedKeySystem(kExternal));
    return false;
#else
    return true;
#endif
}

class TestMediaClient : public MediaClient {
public:
    TestMediaClient();
    ~TestMediaClient() override;

    // MediaClient implementation.
    void AddKeySystemsInfoForUMA(
        std::vector<KeySystemInfoForUMA>* key_systems_info_for_uma) final;
    bool IsKeySystemsUpdateNeeded() final;
    void AddSupportedKeySystems(std::vector<std::unique_ptr<KeySystemProperties>>*
            key_systems_properties) override;
    void RecordRapporURL(const std::string& metric, const GURL& url) final;
    bool IsSupportedVideoConfig(media::VideoCodec codec,
        media::VideoCodecProfile profile,
        int level) final;

    // Helper function to test the case where IsKeySystemsUpdateNeeded() is true
    // after AddSupportedKeySystems() is called.
    void SetKeySystemsUpdateNeeded();

    // Helper function to disable "kExternal" key system support so that we can
    // test the key system update case.
    void DisableExternalKeySystemSupport();

private:
    bool is_update_needed_;
    bool supports_external_key_system_;
};

TestMediaClient::TestMediaClient()
    : is_update_needed_(true)
    , supports_external_key_system_(true)
{
}

TestMediaClient::~TestMediaClient()
{
}

void TestMediaClient::AddKeySystemsInfoForUMA(
    std::vector<KeySystemInfoForUMA>* key_systems_info_for_uma)
{
    key_systems_info_for_uma->push_back(
        media::KeySystemInfoForUMA(kUsesAes, kUseAesNameForUMA));
    key_systems_info_for_uma->push_back(
        media::KeySystemInfoForUMA(kExternal, kExternalNameForUMA));
}

bool TestMediaClient::IsKeySystemsUpdateNeeded()
{
    return is_update_needed_;
}

void TestMediaClient::AddSupportedKeySystems(
    std::vector<std::unique_ptr<KeySystemProperties>>* key_systems)
{
    DCHECK(is_update_needed_);

    key_systems->emplace_back(new AesKeySystemProperties(kUsesAes));

    if (supports_external_key_system_)
        key_systems->emplace_back(new ExternalKeySystemProperties());

    is_update_needed_ = false;
}

void TestMediaClient::RecordRapporURL(const std::string& /* metric */,
    const GURL& /* url */)
{
    NOTIMPLEMENTED();
}

bool TestMediaClient::IsSupportedVideoConfig(media::VideoCodec codec,
    media::VideoCodecProfile profile,
    int level)
{
    return true;
}

void TestMediaClient::SetKeySystemsUpdateNeeded()
{
    is_update_needed_ = true;
}

void TestMediaClient::DisableExternalKeySystemSupport()
{
    supports_external_key_system_ = false;
}

class PotentiallySupportedNamesTestMediaClient : public TestMediaClient {
    void AddSupportedKeySystems(std::vector<std::unique_ptr<KeySystemProperties>>*
            key_systems_properties) final;
};

void PotentiallySupportedNamesTestMediaClient::AddSupportedKeySystems(
    std::vector<std::unique_ptr<KeySystemProperties>>* key_systems)
{
    // org.w3.clearkey is automatically registered.
    key_systems->emplace_back(new AesKeySystemProperties("com.widevine.alpha"));
    key_systems->emplace_back(
        new AesKeySystemProperties("org.chromium.externalclearkey"));
    key_systems->emplace_back(
        new AesKeySystemProperties("org.chromium.externalclearkey.something"));
    key_systems->emplace_back(
        new AesKeySystemProperties("com.chromecast.something"));
    key_systems->emplace_back(new AesKeySystemProperties("x-something"));
}

class KeySystemsPotentiallySupportedNamesTest : public testing::Test {
protected:
    KeySystemsPotentiallySupportedNamesTest()
    {
        SetMediaClient(&test_media_client_);
    }

    ~KeySystemsPotentiallySupportedNamesTest() override
    {
        // Clear the use of |test_media_client_|, which was set in SetUp().
        SetMediaClient(nullptr);
    }

private:
    PotentiallySupportedNamesTestMediaClient test_media_client_;
};

class KeySystemsTest : public testing::Test {
protected:
    KeySystemsTest()
    {
        vp8_codec_.push_back("vp8");

        vp80_codec_.push_back("vp8.0");

        vp9_codec_.push_back("vp9");

        vp90_codec_.push_back("vp9.0");

        vorbis_codec_.push_back("vorbis");

        vp8_and_vorbis_codecs_.push_back("vp8");
        vp8_and_vorbis_codecs_.push_back("vorbis");

        vp9_and_vorbis_codecs_.push_back("vp9");
        vp9_and_vorbis_codecs_.push_back("vorbis");

        foovideo_codec_.push_back("foovideo");

        foovideo_extended_codec_.push_back("foovideo.4D400C");

        foovideo_dot_codec_.push_back("foovideo.");

        fooaudio_codec_.push_back("fooaudio");

        foovideo_and_fooaudio_codecs_.push_back("foovideo");
        foovideo_and_fooaudio_codecs_.push_back("fooaudio");

        unknown_codec_.push_back("unknown");

        mixed_codecs_.push_back("vorbis");
        mixed_codecs_.push_back("foovideo");

        SetMediaClient(&test_media_client_);
    }

    void SetUp() override
    {
        AddContainerAndCodecMasksForTest();
    }

    ~KeySystemsTest() override
    {
        // Clear the use of |test_media_client_|, which was set in SetUp().
        SetMediaClient(nullptr);
    }

    void UpdateClientKeySystems()
    {
        test_media_client_.SetKeySystemsUpdateNeeded();
        test_media_client_.DisableExternalKeySystemSupport();
    }

    typedef std::vector<std::string> CodecVector;

    const CodecVector& no_codecs() const { return no_codecs_; }

    const CodecVector& vp8_codec() const { return vp8_codec_; }
    const CodecVector& vp80_codec() const { return vp80_codec_; }
    const CodecVector& vp9_codec() const { return vp9_codec_; }
    const CodecVector& vp90_codec() const { return vp90_codec_; }

    const CodecVector& vorbis_codec() const { return vorbis_codec_; }

    const CodecVector& vp8_and_vorbis_codecs() const
    {
        return vp8_and_vorbis_codecs_;
    }
    const CodecVector& vp9_and_vorbis_codecs() const
    {
        return vp9_and_vorbis_codecs_;
    }

    const CodecVector& foovideo_codec() const { return foovideo_codec_; }
    const CodecVector& foovideo_extended_codec() const
    {
        return foovideo_extended_codec_;
    }
    const CodecVector& foovideo_dot_codec() const { return foovideo_dot_codec_; }
    const CodecVector& fooaudio_codec() const { return fooaudio_codec_; }
    const CodecVector& foovideo_and_fooaudio_codecs() const
    {
        return foovideo_and_fooaudio_codecs_;
    }

    const CodecVector& unknown_codec() const { return unknown_codec_; }

    const CodecVector& mixed_codecs() const { return mixed_codecs_; }

private:
    const CodecVector no_codecs_;
    CodecVector vp8_codec_;
    CodecVector vp80_codec_;
    CodecVector vp9_codec_;
    CodecVector vp90_codec_;
    CodecVector vorbis_codec_;
    CodecVector vp8_and_vorbis_codecs_;
    CodecVector vp9_and_vorbis_codecs_;

    CodecVector foovideo_codec_;
    CodecVector foovideo_extended_codec_;
    CodecVector foovideo_dot_codec_;
    CodecVector fooaudio_codec_;
    CodecVector foovideo_and_fooaudio_codecs_;

    CodecVector unknown_codec_;

    CodecVector mixed_codecs_;

    TestMediaClient test_media_client_;
};

// TODO(ddorwin): Consider moving GetPepperType() calls out to their own test.

TEST_F(KeySystemsTest, EmptyKeySystem)
{
    EXPECT_FALSE(IsSupportedKeySystem(std::string()));
    EXPECT_EQ("Unknown", GetKeySystemNameForUMA(std::string()));
}

// Clear Key is the only key system registered in content.
TEST_F(KeySystemsTest, ClearKey)
{
    EXPECT_TRUE(IsSupportedKeySystem(kClearKey));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, no_codecs(), kClearKey));

    EXPECT_EQ("ClearKey", GetKeySystemNameForUMA(kClearKey));
}

TEST_F(KeySystemsTest, ClearKeyWithInitDataType)
{
    EXPECT_TRUE(IsSupportedKeySystem(kClearKey));
    EXPECT_TRUE(
        IsSupportedKeySystemWithInitDataType(kClearKey, EmeInitDataType::WEBM));
    EXPECT_TRUE(
        IsSupportedKeySystemWithInitDataType(kClearKey, EmeInitDataType::KEYIDS));

    // All other InitDataTypes are not supported.
    EXPECT_FALSE(IsSupportedKeySystemWithInitDataType(kClearKey,
        EmeInitDataType::UNKNOWN));
}

// The key system is not registered and therefore is unrecognized.
TEST_F(KeySystemsTest, Basic_UnrecognizedKeySystem)
{
    static const char* const kUnrecognized = "x-org.example.unrecognized";

    EXPECT_FALSE(IsSupportedKeySystem(kUnrecognized));

    EXPECT_EQ("Unknown", GetKeySystemNameForUMA(kUnrecognized));
    EXPECT_FALSE(CanUseAesDecryptor(kUnrecognized));

#if BUILDFLAG(ENABLE_PEPPER_CDMS)
    std::string type;
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
    EXPECT_DEATH(type = GetPepperType(kUnrecognized),
        "x-org.example.unrecognized is not a known system");
#endif
    EXPECT_TRUE(type.empty());
#endif
}

TEST_F(KeySystemsTest, Basic_UsesAesDecryptor)
{
    EXPECT_TRUE(IsSupportedKeySystem(kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, no_codecs(), kUsesAes));

    // No UMA value for this test key system.
    EXPECT_EQ("UseAes", GetKeySystemNameForUMA(kUsesAes));

    EXPECT_TRUE(CanUseAesDecryptor(kUsesAes));
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
    std::string type;
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
    EXPECT_DEATH(type = GetPepperType(kUsesAes),
        "x-org.example.clear is not Pepper-based");
#endif
    EXPECT_TRUE(type.empty());
#endif
}

TEST_F(KeySystemsTest,
    IsSupportedKeySystemWithMediaMimeType_UsesAesDecryptor_TypesContainer1)
{
    // Valid video types.
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp8_codec(), kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp80_codec(), kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp9_codec(), kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp90_codec(), kUsesAes));

    // Audio in a video container.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp8_and_vorbis_codecs(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp9_and_vorbis_codecs(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vorbis_codec(), kUsesAes));

    // Non-Webm codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, foovideo_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, unknown_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, mixed_codecs(), kUsesAes));

    // Valid audio types.
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, no_codecs(), kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, vorbis_codec(), kUsesAes));

    // Non-audio codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kAudioWebM, vp8_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kAudioWebM, vp8_and_vorbis_codecs(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kAudioWebM, vp9_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kAudioWebM, vp9_and_vorbis_codecs(), kUsesAes));

    // Non-Webm codec.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, fooaudio_codec(), kUsesAes));
}

TEST_F(KeySystemsTest, IsSupportedKeySystem_InvalidVariants)
{
    // Case sensitive.
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example.ClEaR"));

    // TLDs are not allowed.
    EXPECT_FALSE(IsSupportedKeySystem("org."));
    EXPECT_FALSE(IsSupportedKeySystem("com"));

    // Extra period.
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clear."));

    // Prefix.
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example."));
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example"));

    // Incomplete.
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clea"));

    // Extra character.
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clearz"));

    // There are no child key systems for UsesAes.
    EXPECT_FALSE(IsSupportedKeySystem("x-org.example.clear.foo"));
}

TEST_F(KeySystemsTest, IsSupportedKeySystemWithMediaMimeType_NoType)
{
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        std::string(), no_codecs(), kUsesAes));

    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(std::string(), no_codecs(),
        "x-org.example.foo"));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        std::string(), no_codecs(), "x-org.example.clear.foo"));
}

// Tests the second registered container type.
// TODO(ddorwin): Combined with TypesContainer1 in a future CL.
TEST_F(KeySystemsTest,
    IsSupportedKeySystemWithMediaMimeType_UsesAesDecryptor_TypesContainer2)
{
    // Valid video types.
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, no_codecs(), kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_codec(), kUsesAes));

    // Audio in a video container.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_and_fooaudio_codecs(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, fooaudio_codec(), kUsesAes));

    // Extended codecs fail because this is handled by SimpleWebMimeRegistryImpl.
    // They should really pass canPlayType().
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_extended_codec(), kUsesAes));

    // Invalid codec format.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_dot_codec(), kUsesAes));

    // Non-container2 codec.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, vp8_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, unknown_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, mixed_codecs(), kUsesAes));

    // Valid audio types.
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, no_codecs(), kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, fooaudio_codec(), kUsesAes));

    // Non-audio codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, foovideo_codec(), kUsesAes));
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, foovideo_and_fooaudio_codecs(), kUsesAes));

    // Non-container2 codec.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, vorbis_codec(), kUsesAes));
}

//
// Non-AesDecryptor-based key system.
//

TEST_F(KeySystemsTest, Basic_ExternalDecryptor)
{
    if (!CanRunExternalKeySystemTests())
        return;

    EXPECT_TRUE(IsSupportedKeySystem(kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, no_codecs(), kExternal));

    EXPECT_FALSE(CanUseAesDecryptor(kExternal));
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
    EXPECT_EQ("application/x-ppapi-external-cdm", GetPepperType(kExternal));
#endif // BUILDFLAG(ENABLE_PEPPER_CDMS)
}

TEST_F(
    KeySystemsTest,
    IsSupportedKeySystemWithMediaMimeType_ExternalDecryptor_TypesContainer1)
{
    if (!CanRunExternalKeySystemTests())
        return;

    // Valid video types.
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, no_codecs(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp8_codec(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp80_codec(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp9_codec(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp90_codec(), kExternal));

    // Audio in a video container.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp8_and_vorbis_codecs(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vp9_and_vorbis_codecs(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, vorbis_codec(), kExternal));

    // Non-Webm codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, foovideo_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, unknown_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, mixed_codecs(), kExternal));

    // Valid audio types.
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, no_codecs(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, vorbis_codec(), kExternal));

    // Non-audio codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, vp8_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, vp8_and_vorbis_codecs(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, vp9_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, vp9_and_vorbis_codecs(), kExternal));

    // Non-Webm codec.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioWebM, fooaudio_codec(), kExternal));
}

TEST_F(
    KeySystemsTest,
    IsSupportedKeySystemWithMediaMimeType_ExternalDecryptor_TypesContainer2)
{
    if (!CanRunExternalKeySystemTests())
        return;

    // Valid video types.
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, no_codecs(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_codec(), kExternal));

    // Audio in a video container.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_and_fooaudio_codecs(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, fooaudio_codec(), kExternal));

    // Extended codecs fail because this is handled by SimpleWebMimeRegistryImpl.
    // They should really pass canPlayType().
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_extended_codec(), kExternal));

    // Invalid codec format.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, foovideo_dot_codec(), kExternal));

    // Non-container2 codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, vp8_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, unknown_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithMediaMimeType(
        kVideoFoo, mixed_codecs(), kExternal));

    // Valid audio types.
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, no_codecs(), kExternal));
    EXPECT_TRUE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, fooaudio_codec(), kExternal));

    // Non-audio codecs.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, foovideo_codec(), kExternal));
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, foovideo_and_fooaudio_codecs(), kExternal));

    // Non-container2 codec.
    EXPECT_FALSE(IsSupportedKeySystemWithAudioMimeType(
        kAudioFoo, vorbis_codec(), kExternal));
}

TEST_F(KeySystemsTest, KeySystemNameForUMA)
{
    EXPECT_EQ("ClearKey", GetKeySystemNameForUMA(kClearKey));

    // External Clear Key never has a UMA name.
    if (CanRunExternalKeySystemTests())
        EXPECT_EQ("Unknown", GetKeySystemNameForUMA(kExternalClearKey));
}

TEST_F(KeySystemsTest, KeySystemsUpdate)
{
    EXPECT_TRUE(IsSupportedKeySystem(kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, no_codecs(), kUsesAes));

    if (CanRunExternalKeySystemTests()) {
        EXPECT_TRUE(IsSupportedKeySystem(kExternal));
        EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(kVideoWebM, no_codecs(),
            kExternal));
    }

    UpdateClientKeySystems();

    EXPECT_TRUE(IsSupportedKeySystem(kUsesAes));
    EXPECT_TRUE(IsSupportedKeySystemWithMediaMimeType(
        kVideoWebM, no_codecs(), kUsesAes));
    if (CanRunExternalKeySystemTests())
        EXPECT_FALSE(IsSupportedKeySystem(kExternal));
}

TEST_F(KeySystemsPotentiallySupportedNamesTest, PotentiallySupportedNames)
{
    EXPECT_FALSE(IsSupportedKeySystem("org.w3"));
    EXPECT_FALSE(IsSupportedKeySystem("org.w3."));
    EXPECT_FALSE(IsSupportedKeySystem("org.w3.clearke"));
    EXPECT_TRUE(IsSupportedKeySystem("org.w3.clearkey"));
    EXPECT_FALSE(IsSupportedKeySystem("org.w3.clearkeys"));

    EXPECT_FALSE(IsSupportedKeySystem("com.widevine"));
    EXPECT_FALSE(IsSupportedKeySystem("com.widevine."));
    EXPECT_FALSE(IsSupportedKeySystem("com.widevine.alph"));
    EXPECT_TRUE(IsSupportedKeySystem("com.widevine.alpha"));
    EXPECT_FALSE(IsSupportedKeySystem("com.widevine.beta"));
    EXPECT_FALSE(IsSupportedKeySystem("com.widevine.alphabeta"));
    EXPECT_FALSE(IsSupportedKeySystem("com.widevine.alpha.beta"));

    EXPECT_FALSE(IsSupportedKeySystem("org.chromium"));
    EXPECT_FALSE(IsSupportedKeySystem("org.chromium."));
    EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearke"));
    EXPECT_TRUE(IsSupportedKeySystem("org.chromium.externalclearkey"));
    EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearkeys"));
    EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearkey."));
    EXPECT_TRUE(IsSupportedKeySystem("org.chromium.externalclearkey.something"));
    EXPECT_FALSE(
        IsSupportedKeySystem("org.chromium.externalclearkey.something.else"));
    EXPECT_FALSE(IsSupportedKeySystem("org.chromium.externalclearkey.other"));
    EXPECT_FALSE(IsSupportedKeySystem("org.chromium.other"));

    EXPECT_FALSE(IsSupportedKeySystem("com.chromecast"));
    EXPECT_FALSE(IsSupportedKeySystem("com.chromecast."));
    EXPECT_TRUE(IsSupportedKeySystem("com.chromecast.something"));
    EXPECT_FALSE(IsSupportedKeySystem("com.chromecast.something.else"));
    EXPECT_FALSE(IsSupportedKeySystem("com.chromecast.other"));

    EXPECT_FALSE(IsSupportedKeySystem("x-"));
    EXPECT_TRUE(IsSupportedKeySystem("x-something"));
    EXPECT_FALSE(IsSupportedKeySystem("x-something.else"));
    EXPECT_FALSE(IsSupportedKeySystem("x-other"));
}

} // namespace media
